package model

import (
	"dealcenter/utils/logx"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
	"github.com/spf13/viper"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
	"gorm.io/gorm/schema"
	"strings"
	"time"
)

var GlobalDB *gorm.DB

func InitDB() {
	var (
		host     = viper.GetString("mysql.host")
		port     = viper.GetString("mysql.port")
		database = viper.GetString("mysql.database")
		username = viper.GetString("mysql.username")
		password = viper.GetString("mysql.password")
		charset  = viper.GetString("mysql.charset")
	)
	dsn := strings.Join([]string{username, ":", password, "@tcp(", host, ":", port, ")/", database, "?charset=" + charset + "&parseTime=true"}, "")
	if err := dbLink(dsn); err != nil {
		logx.LogrusObj.Fatalln(errors.Wrap(err, "[GORM]"))
	}
}

func dbLink(dsn string) error {
	gormDB, err := gorm.Open(
		mysql.New(
			mysql.Config{
				DSN:                      dsn,
				DefaultStringSize:        256,  // string 类型字段的默认长度
				DisableDatetimePrecision: true, // 禁用 datetime 精度，MySQL 5.6 之前的数据库不支持
				DontSupportRenameIndex:   true, // 重命名索引时采用删除并新建的方式，MySQL 5.7 之前的数据库和 MariaDB 不支持重命名索引
				//DontSupportRenameColumn:   true,     // 用 `change` 重命名列，MySQL 8 之前的数据库和 MariaDB 不支持重命名列
				SkipInitializeWithVersion: false, // 根据版本自动配置
			}),
		&gorm.Config{
			Logger: newGormLogger(gin.Mode()),
			NamingStrategy: schema.NamingStrategy{
				SingularTable: true,
				TablePrefix:   "v2_",
			},
			//SkipDefaultTransaction:                   false,	// 默认事务
			DisableForeignKeyConstraintWhenMigrating: true, // 取消物理外键
		})
	if err != nil {
		return errors.Wrap(err, "database connect failure")
	}

	// 设置数据库资源池
	sqlDB, _ := gormDB.DB()
	sqlDB.SetMaxIdleConns(20)  // 设置连接池，空闲
	sqlDB.SetMaxOpenConns(100) // 打开
	sqlDB.SetConnMaxLifetime(time.Second * 30)
	GlobalDB = gormDB

	// 迁移
	return migration()
}

// ============================================= 自定义 Logger =============================================

// 实现 gorm.writer 接口
type gormWriter struct {
	logrusObj *logrus.Logger
}

func (w *gormWriter) Printf(format string, v ...interface{}) {
	logstr := fmt.Sprintf(format, v...)
	w.logrusObj.Info(logstr)
}

func newGormLogger(level string) logger.Interface {
	var logLevel logger.LogLevel
	switch level {
	case gin.DebugMode:
		logLevel = logger.Warn
		break
	case gin.ReleaseMode:
		logLevel = logger.Error
		break
	default:
		logLevel = logger.Warn
	}

	return logger.New(
		&gormWriter{
			logrusObj: logx.LogrusObj,
		},
		logger.Config{
			SlowThreshold:             time.Millisecond * 10,
			Colorful:                  false,
			IgnoreRecordNotFoundError: false,
			LogLevel:                  logLevel,
		})
}
